package com.xunshibao.service.message.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.xunshibao.bll.message.MessageLogic;
import com.xunshibao.core.dao.TransactionItem;
import com.xunshibao.core.dao.page.Pagination;
import com.xunshibao.dao.message.MessageDao;
import com.xunshibao.dao.user.UserDao;
import com.xunshibao.entity.message.Message;
import com.xunshibao.entity.message.MsgRelation;
import com.xunshibao.entity.message.MsgReply;
import com.xunshibao.entity.user.UserLogin;
import com.xunshibao.service.message.MessageCatType;
import com.xunshibao.service.message.MessageDRO;
import com.xunshibao.service.message.MessageService;
import com.xunshibao.service.message.MessageSourceType;
import com.xunshibao.service.message.MessageStatus;
import com.xunshibao.util.DateUtil;

@Service("test")
public class MessageServiceImpl implements MessageService {
	private MessageLogic logic;
	private MessageDao msgDao;
	private UserDao userDao;

	@Autowired
	public void setLogic(MessageLogic logic) {
		this.logic = logic;
	}

	@Autowired
	public void setMsgDao(MessageDao msgDao) {
		this.msgDao = msgDao;
	}

	@Autowired
	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}

	@Override
	public boolean sendUserMessage(Long sid, List<Long> rids, String senderName, String title, String content) {
		return sendMessage(sid, rids, senderName, title, content, MessageCatType.USER);
	}

	@Override
	public boolean sendSystemMessage(List<Long> rids, String title, String content) {
		return sendMessage(0l, rids, "system", title, content, MessageCatType.SYSTEM);
	}

	private boolean sendMessage(Long sid, List<Long> rids, String senderName, String title, String content, MessageCatType type) {
		if(rids == null) {
			return false;
		}
		int now = DateUtil.getNow();
		Message msg = logic.saveMessages(sid, now, senderName, title, content);
		msgDao.save(msg);
		List<TransactionItem> items = new ArrayList<TransactionItem>(5);
		for (Long rid : rids) {
			// 发送者和接收者之间的关系
			items.addAll(logic.saveRelations(sid, rid, msg.getMsgId(), now, type));// 一次加了2个
			// 更新消息接收者的新消息数量
			items.addAll(logic.updateMsgNums(rid, type));// 一次加了2个
		}
		items.add(logic.saveReplies(msg.getMsgId(), sid, now, senderName, title, content));// 一次加了1个

		int effectRows = msgDao.execTransaction(items);
		if (effectRows > 0)
			return true;
		return false;
	}

	@Override
	public MessageDRO listUserInbox(Long uid, int pageNo, int pageSize) {
		return getMsgs(uid, MessageCatType.USER, MessageSourceType.RECEIVER, pageNo, pageSize);
	}

	@Override
	public MessageDRO listSystem(Long uid, int pageNo, int pageSize) {
		return getMsgs(uid, MessageCatType.SYSTEM, MessageSourceType.RECEIVER, pageNo, pageSize);
	}

	@Override
	public MessageDRO listUserOutbox(Long uid, int pageNo, int pageSize) {
		// 收件箱中所有消息的数量
		int total = logic.msgCount(uid, MessageCatType.USER, MessageSourceType.SENDER, false);
		// 获取关联关系中消息的编号
		Pagination page = logic.getMsgRelation(uid, MessageCatType.USER, MessageSourceType.RECEIVER, pageNo, pageSize);

		return prepareMsgDRO(0, total, page);
	}

	public MessageDRO getMsgs(Long uid, MessageCatType type, MessageSourceType source, int pageNo, int pageSize) {
		// 新消息数量
		int newTotal = logic.msgCount(uid, type, source, true);
		// 收件箱中所有消息的数量
		int total = logic.msgCount(uid, type, source, false);
		// 获取关联关系中消息的编号
		Pagination page = logic.getMsgRelation(uid, type, source, pageNo, pageSize);
		return prepareMsgDRO(newTotal, total, page);
	}

	private MessageDRO prepareMsgDRO(int newTotal, int total, Pagination page) {
		MessageDRO dro = null;
		if (page != null && page.getList() != null) {
			@SuppressWarnings("unchecked")
			List<MsgRelation> msgRelationList = (List<MsgRelation>) page.getList();
			List<Long> msgIdList = new ArrayList<Long>(msgRelationList.size());
			Map<Long, Message> msgMap = new HashMap<Long, Message>();
			if(msgRelationList == null) {
				msgRelationList = Collections.emptyList();
			}
			for (MsgRelation relation : msgRelationList) {
				msgIdList.add(relation.getMsgid());
			}
			List<Message> msgList = logic.getMsgList(msgIdList);
			if(msgList == null) {
				msgList = Collections.emptyList();
			}
			for (Message msg : msgList) {
				msgMap.put(msg.getMsgId(), msg);
			}
			dro = new MessageDRO(page, total, newTotal);
			// 消息关联数组，用于存放消息的状态信息
//			dro.setMessages(msgMap);
		}
		return dro;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<MsgReply> readMsg(Long rid, Long uid, int pmnum) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("rid", rid);
		params.put("uid", uid);
		// 取得关联中属于当前用户的消息
		String hql = "select new MsgRelation(r.msgid) from MsgRelation r where r.userid=:uid and r.relationId=:rid";
		MsgRelation relation = (MsgRelation) this.msgDao.findSingle(hql, params);
		// 获取消息的具体内容
		if (relation != null) {
			List<TransactionItem> trans = new ArrayList<TransactionItem>(2);
			// 更新回复的状态
			trans.add(logic.updateReplyStatus(Arrays.asList(rid), MessageStatus.READED));
			// 更新回复消息的查看时间
			trans.add(logic.updateReplyViewDate(uid, Arrays.asList(rid), DateUtil.getNow()));
			// TODO 更新msconfig中新消息的条数
			if(pmnum > 0) {
				params.clear();
				params.put("pmnum", pmnum-1);
				params.put("uid", uid);
				hql = "update User u set u.newpm=:pmnum where u.id=:uid";
				trans.add(new TransactionItem(hql, params));
			}
			this.msgDao.execTransaction(trans);// 执行更新操作
			params.clear();
			params.put("msgId", relation.getMsgid());
			hql = "select r from MsgReply r where r.msgId=:msgId order by r.createtime desc";
			
			
			return (List<MsgReply>) this.msgDao.find(hql, params);
		} else {
			return null;
		}
	}

	@Override
	public boolean replyMsg(Long mid, Long uid, String username, String content) {
		// TODO Auto-generated method stub
		// 1. 插入回复记录
		// 2. 更新message的内容
		// 3. 更新message_relations内容
		int now = DateUtil.getNow();
		List<TransactionItem> transItems = logic.replyMsg(mid, uid, username, now, content);
		// 4. 更新ms_config， members消息数
		// TODO 获得接受消息的用户编号
		// SELECT * FROM pw_ms_relations WHERE MID =
		// '3',判断其中的ID是否和当前用户的ID相同，不同的就是收件人
		String hql = "select new MsgRelation(r.msgid, r.userid) from MsgRelation r where r.msgid=:msgId ";
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("msgId", mid);
		List<MsgRelation> relations = (List<MsgRelation>) this.msgDao.find(hql, params);

		Long receiverId = 0l;
		if(relations == null) {
			relations = Collections.emptyList();
		}
		for (MsgRelation r : relations) {
			if (!r.getUserid().equals(uid)) {
				receiverId = r.getUserid();
				break;
			}
		}
		// 如果接受消息的用户存在
		if (!receiverId.equals(0l)) {
			logic.updateMsgNums(receiverId, MessageCatType.USER);
			Object retV = this.msgDao.execTransaction(transItems);
			if (retV != null) {
				return true;
			}
		}

		return false;
	}

	@Override
	public boolean delete(Long rid, Long uid) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("rid", rid);
		String hql = "select new MsgRelation(r.msgid) from MsgRelation r where r.relationId=:rid";
		MsgRelation relation = (MsgRelation) this.msgDao.findSingle(hql, params);
		if (relation != null) {
			List<TransactionItem> transItems = this.logic.delete(rid, uid, relation.getMsgid());
			Object retV = this.msgDao.execTransaction(transItems);
			if (retV != null) {
				return true;
			}
		}

		return false;
	}

	@Override
	public Long getUserIdByName(String username) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("username", username);
		String hql = "select new UserLogin(login.uid, login.username) from UserLogin login where login.username=:username";
		UserLogin login = (UserLogin) this.userDao.findSingle(hql, params);
		if (login != null) {
			return login.getUid();
		}
		return null;
	}
}
